package com.xinqi.modules.course.clazz.service.impl;

import cn.hutool.core.util.DesensitizedUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xinqi.common.base.enums.YesNoEnum;
import com.xinqi.common.base.enums.YesNoNumberEnum;
import com.xinqi.common.base.error.CommonErrors;
import com.xinqi.common.base.response.PageInfo;
import com.xinqi.common.base.response.Param;
import com.xinqi.common.base.response.R;
import com.xinqi.common.base.user.Account;
import com.xinqi.common.base.utils.lambda.Lambdas;
import com.xinqi.common.base.utils.spring.Spring;
import com.xinqi.common.core.enums.ChatRemindTypeEnum;
import com.xinqi.common.core.enums.ClassRoleEnum;
import com.xinqi.common.core.enums.StudentSwitchType;
import com.xinqi.common.core.utils.MessageUtils;
import com.xinqi.common.core.utils.StringUtils;
import com.xinqi.common.green.utils.SensitiveWordUtils;
import com.xinqi.common.mybatis.data.service.impl.BaseServiceImpl;
import com.xinqi.common.mybatis.utils.Pages;
import com.xinqi.common.mybatis.utils.Queries;
import com.xinqi.common.satoken.utils.LoginHelper;
import com.xinqi.modules.chat.chat.group.client.RemoteChatClient;
import com.xinqi.modules.course.clazz.convert.ClassGroupStudentConvert;
import com.xinqi.modules.course.clazz.convert.ClassJoinAuditConvert;
import com.xinqi.modules.course.clazz.convert.ClassStudentConvert;
import com.xinqi.modules.course.clazz.domain.ClassJoinAuditEntity;
import com.xinqi.modules.course.clazz.domain.ClassStudentEntity;
import com.xinqi.modules.course.clazz.dto.ClassStudentAuditData;
import com.xinqi.modules.course.clazz.dto.req.*;
import com.xinqi.modules.course.clazz.dto.rsp.*;
import com.xinqi.modules.course.clazz.manager.ClassJoinAuditManager;
import com.xinqi.modules.course.clazz.mapper.ClassStudentMapper;
import com.xinqi.modules.course.clazz.service.*;
import com.xinqi.modules.course.clazz.thread.ClassMessageSyncService;
import com.xinqi.modules.course.course.constant.CourseConstants;
import com.xinqi.modules.course.course.enums.ClassAuditJsonParamEnum;
import com.xinqi.modules.course.course.enums.ClassStudentRelationshipEnum;
import com.xinqi.modules.course.course.enums.clazz.ClassAuditStatusEnum;
import com.xinqi.modules.course.course.enums.clazz.ClassOperationLogTypeEnum;
import com.xinqi.modules.user.user.client.UserClient;
import com.xinqi.modules.user.user.dto.req.UserImitateDTO;
import com.xinqi.modules.user.user.dto.req.UserImitateUpdateDTO;
import com.xinqi.modules.user.user.dto.req.UserQueryDTO;
import com.xinqi.modules.user.user.dto.rsp.UserResultDTO;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 班级学生表服务层实现
 *
 * @author: system
 * @date: 2023/01/17
 */
@Service("classStudentService")
@RequiredArgsConstructor
public class ClassStudentServiceImpl extends BaseServiceImpl<ClassStudentMapper, ClassStudentEntity> implements ClassStudentService {

    private final ClassStudentConvert classStudentConvert;
    @Lazy
    private final ClassGroupStudentService classGroupStudentService;
    @Lazy
    private final ClassService classService;
    private final ClassStudentMapper classStudentMapper;
    private final ClassGroupStudentConvert classGroupStudentConvert;
    @Lazy
    private final ClassJoinAuditConvert classJoinAuditConvert;
    private final UserClient userClient;
    @Lazy
    private final ClassJoinAuditService classJoinAuditService;

    private final ClassJoinAuditManager classJoinAuditManager;
    @Lazy
    private final ClassOperationLogService classOperationLogService;
    @Lazy
    private final ChatRemindSyncService chatRemindSyncService;
    @Lazy
    private final ClassMessageSyncService classMessageSyncService;
    @Lazy
    private final ClassStudentService classStudentService;

    private final ClassMqService classMqService;
    private final RemoteChatClient remoteChatClient;

    /**
     * 分页查询 班级学生表数据
     */
    @Override
    @DS("slaver")
    public PageInfo<ClassStudentResultDTO> page(Param pageable, ClassStudentQueryDTO query) {
        IPage<ClassStudentEntity> page = page(Pages.page(pageable), wrapper(query));
        PageInfo<ClassStudentResultDTO> info = Pages.convert(page, classStudentConvert::convert);
        // 校验是否可以编辑
        this.checkEdit(info.getRows(), query.getClassId());
        return info;
    }

    // 校验是否可以编辑
    private void checkEdit(List<ClassStudentResultDTO> list, Long classId) {
        // 获取用户在班级信息
        ClassStudentResultDTO student = this.findByStudentId(classId, LoginHelper.getUserId());
        if (Objects.nonNull(student)) {
            list.forEach(item -> {
                if (Objects.equals(YesNoNumberEnum.YES.getCode(), student.getIsTeacher())) {
                    if (Objects.equals(student.getStudentId(), item.getStudentId())) {
                        item.setIsEdit(YesNoNumberEnum.YES.getCode());
                    }
                } else {
                    if (Objects.equals(student.getPatStuRefId(), item.getStudentId())) {
                        item.setIsEdit(YesNoNumberEnum.YES.getCode());
                    }
                }
            });
        }
    }

    @Override
    public List<ClassStudentResultDTO> findByClassId(Long classId) {
        ClassStudentQueryDTO query = new ClassStudentQueryDTO();
        query.setClassId(classId);
        query.setIsRelationalStudent(YesNoNumberEnum.YES.getCode());
        return find(query);
    }

    /**
     * 删除主学生，需要先删除主学生，再删除从学生
     *
     * @param user    用户
     * @param classId 班级id
     * @param dtoList 要删除的列表
     * @return Boolean
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean teacherRemoveMasterBatch(Account user, Long classId, List<ClassStudentDeleteDTO> dtoList) {
        CommonErrors.BAD_REQUEST.check(CollectionUtils.isNotEmpty(dtoList), "请选择要移除的学生");
        List<Long> masterIdList = dtoList.stream().map(ClassStudentDeleteDTO::getId).collect(Collectors.toList());
        this.removeRelationalStudentBatch(classId, masterIdList);
        this.removeMasterBatch(user, classId, masterIdList);
        return true;
    }

    /**
     * 查询 班级学生表数据
     */
    @Override
    public List<ClassStudentResultDTO> find(ClassStudentQueryDTO query) {
        return list(wrapper(query)).stream().map(classStudentConvert::convert).collect(Collectors.toList());
    }

    private LambdaQueryWrapper<ClassStudentEntity> wrapper(ClassStudentQueryDTO query) {
        LambdaQueryWrapper<ClassStudentEntity> wrapper = Queries.lambda();
        Queries.accept(query.getId(), v -> wrapper.eq(ClassStudentEntity::getId, v));
        Queries.accept(query.getCourseId(), v -> wrapper.eq(ClassStudentEntity::getCourseId, v));
        Queries.accept(query.getClassId(), v -> wrapper.eq(ClassStudentEntity::getClassId, v));
        Queries.accept(query.getClassRole(), v -> wrapper.eq(ClassStudentEntity::getClassRole, v));
        Queries.accept(query.getStudentId(), v -> wrapper.eq(ClassStudentEntity::getStudentId, v));
        Queries.accept(query.getIsTeacher(), v -> wrapper.eq(ClassStudentEntity::getIsTeacher, v));
        Queries.accept(query.getIsRelationalStudent(), v -> wrapper.eq(ClassStudentEntity::getIsRelationalStudent, v));
        Queries.accept(query.getPatStuRefId(), v -> wrapper.eq(ClassStudentEntity::getPatStuRefId, v));
        return wrapper;
    }

    /**
     * 根据id查询 班级学生表数据
     */
    @Override
    public ClassStudentResultDTO findById(Long id) {
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(id), "ID不能为空");
        return baseMapper.findDetailById(id);
    }

    /**
     * 成员管理学生信息显示问题：
     * 1.老师、助教身份，可以查看所有成员手机号
     * 2.学生身份，可以查看老师和助教手机号。 学生无法查看其他学生的手机号，（成员管理列表，成员管理列表进入的详情页）
     *
     * @param id
     * @return
     */
    @Override
    public ClassStudentResultDTO findDetailByIdAndDesensitized(Long id) {
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(id), "ID不能为空");
        ClassStudentResultDTO result = baseMapper.findDetailById(id);

        if (Objects.nonNull(result)) {
            //模拟用户信息
            ClassStudentResultDTO classMasterStudent = this.findVirtualClassStudentByClassIdAndUserId(result.getClassId(), LoginHelper.getUserId());
            Long studentId = Objects.isNull(classMasterStudent) ? LoginHelper.getUserId() : classMasterStudent.getStudentId();

            ClassStudentResultDTO studentResultDTO = this.findAllRolesStudentByClassIdAndStudentId(result.getClassId(), studentId);
            //查看的人和被看的人都是学生,并且不是学生自己的时候要脱敏
            if (Objects.nonNull(studentResultDTO) && Objects.equals(studentResultDTO.getIsTeacher(), YesNoEnum.NO.ordinal()) && Objects.equals(result.getIsTeacher(), YesNoEnum.NO.ordinal()) && !Objects.equals(studentId, result.getStudentId())) {
                result.setMobile(DesensitizedUtil.mobilePhone(result.getMobile()));
            }

            //登录用户（有可能是老师、或关系用户）
            ClassStudentResultDTO loginStudent = this.findByClassIdAndStudentId(result.getClassId(), LoginHelper.getUserId());
            if (Objects.nonNull(loginStudent) && Objects.nonNull(classMasterStudent) && Objects.equals(classMasterStudent.getStudentId(), loginStudent.getPatStuRefId())) {
                //当前登录人与模拟学生之间的亲属关系（师生关系不算）
                result.setKinship(loginStudent.getRelationship());
            }
        }

        return result;
    }

    /**
     * 新增 班级学生表数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long insert(ClassStudentCreateDTO dto) {
        // 报名信息敏感词校验
        if (!SensitiveWordUtils.checkSensitiveWord(JSON.toJSONString(dto.getAuditContent()))) {
            CommonErrors.BAD_REQUEST.check(false, MessageUtils.message("green.submit.text.message"));
        }
        ClassStudentEntity entity = classStudentConvert.create(dto);
        super.save(entity);
        return entity.getId();
    }

    /**
     * 根据id修改 班级学生表数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateById(ClassStudentUpdateDTO dto) {
        ClassStudentEntity old = Optional.ofNullable(getById(dto.getId())).orElseThrow(() -> CommonErrors.BAD_REQUEST.asException("数据不存在"));
        ClassStudentEntity entity = classStudentConvert.update(dto);
        return updateById(entity);
    }

    /**
     * 根据id删除 班级学生表数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteById(Long id) {
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(id), "ID不能为空");
        return removeById(id);
    }

    /**
     * 根据id删除 班级学生表数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteById(ClassStudentDeleteDTO dto) {
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(dto.getId()), "ID不能为空");
        return deleteById(dto.getId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean teacherAddStudent(ClassStudentCreateDTO dto) {
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(dto.getCourseId()), "课程ID不能为空");
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(dto.getClassId()), "班级ID不能为空");
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(dto.getStudentId()), "学生ID不能为空");
        // 报名信息敏感词校验
        if (Objects.nonNull(dto.getAuditContent())) {
            if (!SensitiveWordUtils.checkSensitiveWord(JSON.toJSONString(dto.getAuditContent()))) {
                CommonErrors.BAD_REQUEST.check(false, MessageUtils.message("green.submit.text.message"));
            }
        }

        //解析审核数据
        ClassAuditJsonParamDTO auditJson = classJoinAuditConvert.convertParam(dto.getAuditContent());

        //班级学生姓名判重
        ClassStudentResultDTO masterExist = this.findByClassIdAndStudentName(dto.getClassId(), auditJson.getStudentName());
        boolean check = Objects.isNull(masterExist) || Objects.equals(auditJson.getStudentName(), masterExist.getStudentName()) && Objects.equals(auditJson.getMobile(), masterExist.getMobile());
        CommonErrors.BAD_REQUEST.check(check, "学生姓名在班级中已存在");

        //判断虚拟学生是否有账号，如果有账号，说明已经有关系用户绑定过学生
        UserResultDTO userResultDTO = this.checkImitateUserAccount(auditJson.getMobile(), auditJson.getStudentName());

        //判断关系用户是否已加班
        Boolean isInClass = this.checkUserIsInClass(dto.getClassId(), dto.getStudentId());

        //有账号
        if (Objects.nonNull(userResultDTO)) {
            if (isInClass) {
                throw CommonErrors.BAD_REQUEST.asException("已加入班级，如需绑定其他学生请更换手机号");
            } else {
                Boolean exist = this.checkUserIsInClass(dto.getClassId(), userResultDTO.getId());
                if (exist) {
                    this.addRelationStudent(dto, auditJson, dto.getStudentId(), userResultDTO.getId());
                } else {
                    this.addCoupleStudents(dto, auditJson, dto.getStudentId(), userResultDTO.getId());
                }
            }
        } else {
            if (isInClass) {
                throw CommonErrors.BAD_REQUEST.asException("已加入班级，如需绑定其他学生请更换手机号");
            } else {
                //创建用户
                userResultDTO = this.imitateUser(auditJson.getMobile(), auditJson.getStudentName());
                this.addCoupleStudents(dto, auditJson, dto.getStudentId(), userResultDTO.getId());
            }
        }

        return true;
    }

    /**
     * 添加关系用户到班级中,并绑定学生id为关系id
     *
     * @param dto        ClassStudentCreateDTO
     * @param auditJson  解析出来的json串
     * @param relationId 关系学生id
     * @param studentId  虚拟学生id
     */
    @Transactional(rollbackFor = Exception.class)
    public void addRelationStudent(ClassStudentCreateDTO dto, ClassAuditJsonParamDTO auditJson, Long relationId, Long studentId) {
        //将关系用户加入到班级中
        this.autoAuditAndIntoClass(dto.getCourseId(), dto.getClassId(), relationId, dto.getAuditContent(), YesNoEnum.YES.ordinal(), studentId, auditJson);

        //关系用户发消息
        Spring.committed(() -> {
            //关系用户加入班级群
            remoteChatClient.classJoinGroup(dto.getClassId(), relationId);
            // 加班消息发送
            // chatRemindSyncService.acceptPass(dto.getClassId(), relationId, ChatRemindTypeEnum.AUDIT_PASS);
        });
    }

    /**
     * 添加一对虚实学生到班级中
     *
     * @param dto        ClassStudentCreateDTO
     * @param auditJson  解析出来的json串
     * @param relationId 关系学生id
     * @param studentId  虚拟学生id
     */
    @Transactional(rollbackFor = Exception.class)
    public void addCoupleStudents(ClassStudentCreateDTO dto, ClassAuditJsonParamDTO auditJson, Long relationId, Long studentId) {
        //将关系用户加入到班级中
        this.autoAuditAndIntoClass(dto.getCourseId(), dto.getClassId(), relationId, dto.getAuditContent(), YesNoEnum.YES.ordinal(), studentId, auditJson);
        //将虚拟用户加入到班级中
        auditJson.setRelationship(ClassStudentRelationshipEnum.虚拟主学生.getDescribe());
        this.insertStudent(LoginHelper.getUserId(), studentId, dto.getCourseId(), dto.getClassId(), YesNoEnum.NO.ordinal(), 0L, auditJson);

        Spring.committed(() -> {
            //虚拟用户加课后处理
            classMqService.studentJoinClass(dto.getClassId(), studentId);
            //关系用户加入班级群
            remoteChatClient.classJoinGroup(dto.getClassId(), relationId);
            //关系用户发消息
            // chatRemindSyncService.acceptPass(dto.getClassId(), relationId, ChatRemindTypeEnum.AUDIT_PASS);
        });
    }

    @Transactional(rollbackFor = Exception.class)
    public void autoAuditAndIntoClass(Long courseId, Long classId, Long studentId, ClassStudentAuditData auditContent, Integer isRelationalStudent, Long patStuRefId, ClassAuditJsonParamDTO auditJson) {
        this.insertStudent(LoginHelper.getUserId(), studentId, courseId, classId, isRelationalStudent, patStuRefId, auditJson);
        //保存或更新审核数据
        Long auditId = classJoinAuditService.saveOrUpdateByClassIdAndStudentId(classId, studentId, LoginHelper.getUserId(), classJoinAuditConvert.convertToArrayString(classJoinAuditConvert.convertParam(auditContent)), ClassAuditStatusEnum.PASS);
        //添加加课记录
        classOperationLogService.insertStudentOperateLog(courseId, classId, studentId, auditId, ClassOperationLogTypeEnum.MOVE_IN);
    }

    /**
     * 创建虚拟用户
     *
     * @param mobile      手机号
     * @param studentName 学生姓名
     * @return UserResultDTO
     */
    private UserResultDTO imitateUser(String mobile, String studentName) {
        UserImitateDTO userImitateDTO = new UserImitateDTO();
        userImitateDTO.setMobile(mobile);
        userImitateDTO.setNickName(studentName);
        return R.as(userClient.imitateUser(userImitateDTO));
    }

    /**
     * 判断学生是否有账号
     *
     * @param mobile      手机号
     * @param studentName 昵称
     * @return true-有账号，false-无账号
     */
    private UserResultDTO checkImitateUserAccount(String mobile, String studentName) {
        return R.as(userClient.findImitateByMobileAndNickname(mobile, studentName));
    }

    /**
     * 判断关系/虚拟用户是否在班级中
     *
     * @param classId           班级id
     * @param relationStudentId 用关系户id（通常为登录人）
     * @return true-在班级中，false-不在班级中
     */
    private Boolean checkUserIsInClass(Long classId, Long relationStudentId) {
        ClassStudentEntity classStudentEntity = this.selectByClassIdAndStudentId(classId, relationStudentId);
        return !Objects.isNull(classStudentEntity);
    }


    @Override
    public ClassStudentEntity findByClassIdAndStudentId(Long classId, Long studentId, Integer isTeacher) {
        LambdaQueryWrapper<ClassStudentEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ClassStudentEntity::getClassId, classId).eq(ClassStudentEntity::getStudentId, studentId).eq(ClassStudentEntity::getIsTeacher, isTeacher);
        return getOne(wrapper);
    }

    /**
     * 包含老师在内
     *
     * @param classId
     * @param studentId
     * @return
     */
    @Override
    public ClassStudentResultDTO findAllRolesStudentByClassIdAndStudentId(Long classId, Long studentId) {
        LambdaQueryWrapper<ClassStudentEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ClassStudentEntity::getClassId, classId).eq(ClassStudentEntity::getStudentId, studentId);
        return classStudentConvert.convert(getOne(wrapper));
    }

    /**
     * 通过班级ID和学生ID查询班级成员（判断存在于班级中）
     *
     * @Title:
     * @MethodName: selectByClassIdAndStudentId
     * [classId, studentId]
     * @Return com.xinqi.modules.course.clazz.domain.ClassStudentEntity
     * @Exception
     * @Description:
     * @author: yyzhen
     * @date: 2023/3/26 16:39
     */
    @Override
    public ClassStudentEntity selectByClassIdAndStudentId(Long classId, Long studentId) {
        LambdaQueryWrapper<ClassStudentEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ClassStudentEntity::getClassId, classId).eq(ClassStudentEntity::getStudentId, studentId).last("LIMIT 1");
        return getOne(wrapper);
    }

    @Override
    public ClassStudentResultDTO findByClassIdAndStudentId(Long classId, Long studentId) {
        return classStudentConvert.convert(selectByClassIdAndStudentId(classId, studentId));
    }

    /**
     * 权限校验
     * <p>
     * 校验当前学生在班级中的角色，
     * 校验通过，返回学生实体，
     * 校验不通过，CommonErrors.BAD_REQUEST
     *
     * @param classId
     * @param studentId
     * @param classRoles
     * @return
     */
    @Override
    public ClassStudentResultDTO checkRole(Long classId, Long studentId, List<ClassRoleEnum> classRoles) {
        ClassStudentEntity classStudentEntity = this.selectByClassIdAndStudentId(classId, studentId);
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(classStudentEntity), MessageUtils.message("course.comment.is.not.student"));
        if (CollectionUtils.isNotEmpty(classRoles)) {
            CommonErrors.BAD_REQUEST.check(classRoles.contains(classStudentEntity.getClassRole()), MessageUtils.message("course.comment.is.not.permissions"));
        }

        return classStudentConvert.convert(classStudentEntity);
    }

    /**
     * 校验是班级里的学生
     * 老师不算学生
     *
     * @param classId
     * @param userId
     * @return
     */
    @Override
    public Boolean checkIsStudent(Long classId, Long userId) {
        ClassStudentEntity studentEntity = selectByClassIdAndStudentId(classId, userId);
        if (Objects.isNull(studentEntity)) {
            return false;
        }
        if (Objects.equals(ClassRoleEnum.STUDENT, studentEntity.getClassRole())) {
            return true;
        } else if (Objects.equals(ClassRoleEnum.REPRESENTATIVE, studentEntity.getClassRole())) {
            return true;
        } else if (Objects.equals(ClassRoleEnum.ASSISTANT, studentEntity.getClassRole())) {
            return false;
        } else if (Objects.equals(ClassRoleEnum.TEACHER, studentEntity.getClassRole())) {
            return false;
        }
        return false;
    }

    /**
     * 虚拟用户数量
     *
     * @param classId 班级id
     * @return
     */
    @Override
    public int findAddedCountByClassId(Long classId) {
        return this.findClassMasterStudentByClassId(classId).size();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean insertTeacher(Long userId, Long courseId, Long classId) {
        ClassStudentEntity entity = classStudentConvert.convert(courseId, classId, userId);
        entity.setIsTeacher(YesNoEnum.YES.ordinal());
        entity.setIsTop(YesNoEnum.NO.ordinal());
        entity.setClassRole(ClassRoleEnum.TEACHER);
        entity.setCreateBy(LoginHelper.getUserId());
        return save(entity);
    }

    /**
     * @param studentId 学生id
     * @param courseId  课程id
     * @param classId   班级id
     * @return Boolean
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean insertStudent(Long createBy, Long studentId, Long courseId, Long classId, Integer isRelationalStudent, Long patStuRefId, ClassAuditJsonParamDTO auditJsonParamDTO) {
        ClassResultDTO classResultDTO = Optional.ofNullable(classService.findById(classId)).orElseThrow(() -> CommonErrors.BAD_REQUEST.asException("班级数据不存在"));

        CommonErrors.BAD_REQUEST.check(Objects.nonNull(auditJsonParamDTO), "加课信息不能为空");

        int addedCount = classService.findAddedClassCountByUserId(studentId);
        CommonErrors.BAD_REQUEST.check(addedCount < CourseConstants.ClassCount.STUDENT_ADDED_COUNT, "每个用户最多只能加入五十个班级");
        int existingCount = findAddedCountByClassId(classId);
        if (Objects.equals(classResultDTO.getIsStudentCount(), YesNoEnum.YES.ordinal())) {
            CommonErrors.BAD_REQUEST.check(classResultDTO.getStudentCount().compareTo(existingCount) > 0, "课程人数已满");
        } else {
            CommonErrors.BAD_REQUEST.check(existingCount < CourseConstants.ClassStudentCount.MAX_STUDENT_CONTE, "一个班级下最多只能有300人");
        }

        ClassStudentEntity entity = classStudentConvert.convert(courseId, classId, studentId);
        entity.setStudentName(auditJsonParamDTO.getStudentName());
        entity.setRelationship(auditJsonParamDTO.getRelationship());
        entity.setIsRelationalStudent(isRelationalStudent);
        entity.setAuditContent(classJoinAuditConvert.convertToString(auditJsonParamDTO));
        entity.setPatStuRefId(patStuRefId);
        entity.setIsTeacher(YesNoEnum.NO.ordinal());
        entity.setIsTop(YesNoEnum.NO.ordinal());
        entity.setClassRole(ClassRoleEnum.STUDENT);
        entity.setCreateBy(createBy);
        return save(entity);
    }

    @Override
    @DS("slaver")
    public PageInfo<ClassStudentResultDTO> pageList(Page<ClassStudentEntity> page, ClassStudentQueryDTO dto) {
        return Pages.convert(classStudentMapper.pageList(page, dto));
    }

    /**
     * * 成员管理学生信息显示问题：
     * * 1.老师、助教身份，可以查看所有成员手机号
     * * 2.学生身份，可以查看老师和助教手机号。 学生无法查看其他学生的手机号，（成员管理列表，成员管理列表进入的详情页）
     *
     * @param page
     * @param dto
     * @return
     */
    @Override
    @DS("slaver")
    public PageInfo<ClassStudentResultDTO> pageListAndDesensitized(Page<ClassStudentEntity> page, ClassStudentAppQueryDTO dto) {

        PageInfo<ClassStudentResultDTO> pages = Pages.convert(classStudentMapper.pageListByRoles(page, dto, dto.getClassRole().getDataList()));

        if (CollectionUtils.isNotEmpty(pages.getRows())) {
            //模拟用户信息
            ClassStudentResultDTO classMasterStudent = this.findVirtualClassStudentByClassIdAndUserId(dto.getClassId(), LoginHelper.getUserId());
            //如果根据登录人能查到模拟用户信息,则登录人是关系用户
            if (Objects.nonNull(classMasterStudent)) {
                pages.getRows().forEach(item -> {
                    if (Objects.equals(YesNoNumberEnum.NO.getCode(), item.getIsTeacher()) && !Objects.equals(classMasterStudent.getStudentId(), item.getStudentId())) {
                        item.setMobile(DesensitizedUtil.mobilePhone(item.getMobile()));
                    }
                });
            }
        }

        // 校验是否可以编辑
        this.checkEdit(pages.getRows(), dto.getClassId());

        return pages;
    }

    /**
     * 某个分组下，未进组的成员列表,不包括助教和老师
     * 分组以pid为标记
     *
     * @param dto
     * @return
     */
    @Override
    public List<ClassStudentResultDTO> findOutsideStudentList(ClassGroupStudentQueryDTO dto) {
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(dto.getClassId()), "班级ID不能为空");
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(dto.getPid()), "父分组ID不能为空");

        List<ClassStudentResultDTO> classStudentList = findStudentExcludeTeacherByClassIdAndSearchKey(dto.getClassId(), dto.getSearchKey());
        Map<Long, ClassStudentResultDTO> studentEntityMap = classStudentList.stream().collect(Collectors.toMap(ClassStudentResultDTO::getStudentId, v -> v));

        if (CollectionUtils.isNotEmpty(classStudentList)) {
            dto.setGroupId(null);
            List<ClassGroupStudentResultDTO> classGroupStudentList = classGroupStudentService.findStudentList(dto);
            if (CollectionUtils.isNotEmpty(classGroupStudentList)) {
                classGroupStudentList.forEach(s -> studentEntityMap.remove(s.getStudentId()));

                return new ArrayList<>(studentEntityMap.values());
            }

            return classStudentList;
        }

        return Collections.emptyList();
    }

    /**
     * 包括所有的角色
     *
     * @param courseId
     * @return
     */
    @Override
    public List<ClassStudentResultDTO> findAllRolesStudentByCourseId(Long courseId) {
        ClassStudentQueryDTO query = new ClassStudentQueryDTO();
        query.setCourseId(courseId);
        query.setIsRelationalStudent(YesNoNumberEnum.YES.getCode());
        return find(query);
    }

    @Override
    public List<ClassStudentResultDTO> findByCourseIdAndStudentId(Long courseId, Long studentId) {
        ClassStudentQueryDTO query = new ClassStudentQueryDTO();
        query.setCourseId(courseId);
        query.setStudentId(studentId);
        return find(query);
    }

    @Override
    public List<ClassStudentResultDTO> findByCourseIdAndStudentIdAndRoles(Long courseId, Long studentId, List<ClassRoleEnum> classRoles) {
        LambdaQueryWrapper<ClassStudentEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ClassStudentEntity::getCourseId, courseId).eq(ClassStudentEntity::getStudentId, studentId);
        wrapper.in(ClassStudentEntity::getClassRole, classRoles);
        return list(wrapper).stream().map(classStudentConvert::convert).collect(Collectors.toList());
    }

    /**
     * 这里只是没有包含老师
     *
     * @param classId
     * @return
     */
    @Override
    public List<ClassStudentResultDTO> findStudentExcludeTeacher(Long classId) {
        return baseMapper.findByList(classId);
    }

    @Override
    public List<ClassStudentResultDTO> findStudentExcludeTeacherByClassIdAndSearchKey(Long classId, String searchKey) {
        return baseMapper.findListByClassIdAndSearchKey(classId, searchKey);
    }

    @Override
    public List<ClassStudentResultDTO> findByClassIdAndRole(Long classId, ClassRoleEnum classRole) {
        ClassStudentQueryDTO query = new ClassStudentQueryDTO();
        query.setClassRole(classRole.getCode());
        query.setClassId(classId);
        return list(wrapper(query)).stream().map(classStudentConvert::convert).collect(Collectors.toList());
    }

    @Override
    public List<ClassStudentResultDTO> findByClassIdAndRoleAndIsRelationalStudent(Long classId, ClassRoleEnum classRole, Integer isRelationalStudent) {
        ClassStudentQueryDTO query = new ClassStudentQueryDTO();
        query.setClassRole(classRole.getCode());
        query.setClassId(classId);
        query.setIsRelationalStudent(isRelationalStudent);
        return list(wrapper(query)).stream().map(classStudentConvert::convert).collect(Collectors.toList());
    }

    @Override
    public List<ClassStudentEntity> findListByClassId(Long classId) {
        LambdaQueryWrapper<ClassStudentEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ClassStudentEntity::getClassId, classId).eq(ClassStudentEntity::getIsTeacher, YesNoNumberEnum.NO.getCode());
        return list(wrapper);
    }

    @Override
    public List<ClassStudentEntity> findListByIds(List<Long> idList) {
        return classStudentMapper.selectBatchIds(idList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean saveBatch(List<ClassStudentEntity> studentEntityList) {
        return super.updateBatchById(studentEntityList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean addBatch(List<ClassStudentEntity> studentEntityList) {
        return super.saveBatch(studentEntityList);
    }

    /**
     * 虚拟主学生变课代表
     *
     * @param dto 学生实体
     * @return Boolean
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean masterStudentChangeRepresentative(ClassStudentUpdateDTO dto) {
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(dto.getClassId()), "班级ID不能为空");
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(dto.getStudentId()), "学生id不能为空");
        List<ClassStudentResultDTO> representatives = findByClassIdAndRoleAndIsRelationalStudent(dto.getClassId(), ClassRoleEnum.REPRESENTATIVE, YesNoEnum.NO.ordinal());
        CommonErrors.BAD_REQUEST.check(CollectionUtils.isEmpty(representatives), "一个班级只能设置一个主学生为课代表");

        boolean flag = this.saveRole(dto, ClassRoleEnum.REPRESENTATIVE, YesNoEnum.NO.ordinal());

        //设置关系学生为课代表
        List<ClassStudentResultDTO> relationStudentList = this.findRelationStudentByClassIdAndImitateStudentId(dto.getClassId(), dto.getStudentId());
        if (CollectionUtils.isNotEmpty(relationStudentList)) {
            Lambdas.each(relationStudentList, student -> {
                ClassStudentUpdateDTO updateDTO = new ClassStudentUpdateDTO();
                updateDTO.setId(student.getStudentId());
                this.saveRole(updateDTO, ClassRoleEnum.REPRESENTATIVE, YesNoEnum.NO.ordinal());
            });
        }

        Spring.committed(() -> relationStudentList.forEach(relation -> chatRemindSyncService.studentChangeRepresentative(dto.getClassId(), relation.getStudentId(), LoginHelper.getXqLoginUser())));

        return flag;
    }

    /**
     * 关系学生变课代表
     *
     * @param dto
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean relationalStudentChangeRepresentative(ClassStudentUpdateDTO dto) {
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(dto.getClassId()), "班级ID不能为空");
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(dto.getStudentId()), "学生id不能为空");
        List<ClassStudentResultDTO> representatives = findByClassIdAndRoleAndIsRelationalStudent(dto.getClassId(), ClassRoleEnum.REPRESENTATIVE, YesNoEnum.NO.ordinal());
        CommonErrors.BAD_REQUEST.check(CollectionUtils.isEmpty(representatives), "一个班级只能设置一个主学生为课代表");

        boolean flag = this.saveRole(dto, ClassRoleEnum.REPRESENTATIVE, YesNoEnum.NO.ordinal());

        //设置主学生为课代表
        ClassStudentResultDTO masterStudent = this.findVirtualClassStudentByClassIdAndUserId(dto.getClassId(), dto.getStudentId());
        if (Objects.nonNull(masterStudent)) {
            ClassStudentUpdateDTO updateDTO = new ClassStudentUpdateDTO();
            updateDTO.setId(masterStudent.getId());
            this.saveRole(updateDTO, ClassRoleEnum.REPRESENTATIVE, YesNoEnum.NO.ordinal());
        }

        chatRemindSyncService.studentChangeRepresentative(dto.getClassId(), dto.getStudentId(), LoginHelper.getXqLoginUser());

        return flag;
    }

    /**
     * 取消主学生的课代表身份
     *
     * @param dto 学生实体
     * @return
     */
    @Override
    public Boolean masterRepresentativeChangeStudent(ClassStudentUpdateDTO dto) {
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(dto.getClassId()), "班级ID不能为空");
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(dto.getStudentId()), "学生id不能为空");

        boolean flag = this.saveRole(dto, ClassRoleEnum.STUDENT, YesNoEnum.NO.ordinal());

        //取消关系学生的课代表身份
        List<ClassStudentResultDTO> relationStudentList = this.findRelationStudentByClassIdAndImitateStudentId(dto.getClassId(), dto.getStudentId());
        if (CollectionUtils.isNotEmpty(relationStudentList)) {
            Lambdas.each(relationStudentList, student -> {
                ClassStudentUpdateDTO updateDTO = new ClassStudentUpdateDTO();
                updateDTO.setId(student.getStudentId());
                this.saveRole(updateDTO, ClassRoleEnum.STUDENT, YesNoEnum.NO.ordinal());
            });
        }

        chatRemindSyncService.representativeChangeStudent(dto.getClassId(), dto.getStudentId(), LoginHelper.getXqLoginUser());
        return flag;
    }

    /**
     * 取消关系学生的课代表身份
     *
     * @param dto 学生实体
     * @return Boolean
     */
    @Override
    public Boolean relationalRepresentativeChangeStudent(ClassStudentUpdateDTO dto) {
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(dto.getClassId()), "班级ID不能为空");
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(dto.getStudentId()), "学生id不能为空");

        boolean flag = this.saveRole(dto, ClassRoleEnum.STUDENT, YesNoEnum.NO.ordinal());

        //取消主学生的课代表身份
        ClassStudentResultDTO masterStudent = this.findVirtualClassStudentByClassIdAndUserId(dto.getClassId(), dto.getStudentId());
        if (Objects.nonNull(masterStudent)) {
            ClassStudentUpdateDTO updateDTO = new ClassStudentUpdateDTO();
            updateDTO.setId(masterStudent.getId());
            this.saveRole(updateDTO, ClassRoleEnum.STUDENT, YesNoEnum.NO.ordinal());
        }

        chatRemindSyncService.representativeChangeStudent(dto.getClassId(), dto.getStudentId(), LoginHelper.getXqLoginUser());
        return flag;
    }

    /**
     * 学生变助教
     *
     * @param dto 学生实体
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean studentChangeAssistant(Account user, ClassStudentUpdateDTO dto) {
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(dto.getClassId()), "班级ID不能为空");
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(dto.getStudentId()), "学生id不能为空");
        List<ClassStudentResultDTO> representatives = findByClassIdAndRole(dto.getClassId(), ClassRoleEnum.ASSISTANT);
        CommonErrors.BAD_REQUEST.check(CollectionUtils.isEmpty(representatives), "一个班级只能设置一个助教");

        this.saveRole(dto, ClassRoleEnum.ASSISTANT, YesNoEnum.YES.ordinal());

        //删除原来小组中的学生
        boolean flag = classGroupStudentService.deleteByClassIdAndStudentIdList(user, dto.getClassId(), new ArrayList<>(Collections.singletonList(dto.getStudentId())));
        chatRemindSyncService.studentChangeAssistant(dto.getClassId(), dto.getStudentId(), LoginHelper.getXqLoginUser());

        Spring.committed(() -> classMqService.studentIdentitySwitch(dto.getClassId(), dto.getStudentId(), StudentSwitchType.STUDENT_TO_ASSISTANT));

        return flag;
    }

    /**
     * 助教变学生
     *
     * @param dto 学生实体
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean assistantChangeStudent(ClassStudentUpdateDTO dto) {
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(dto.getClassId()), "班级ID不能为空");
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(dto.getStudentId()), "学生id不能为空");
        ClassResultDTO classResultDTO = Optional.ofNullable(classService.findById(dto.getClassId())).orElseThrow(() -> CommonErrors.BAD_REQUEST.asException("班级数据不存在"));
        int addedCount = classService.findAddedClassCountByUserId(dto.getStudentId());
        CommonErrors.BAD_REQUEST.check(addedCount < CourseConstants.ClassCount.STUDENT_ADDED_COUNT, "每个用户最多只能加入五十个班级");
        int existingCount = findAddedCountByClassId(dto.getClassId());
        if (Objects.equals(classResultDTO.getIsStudentCount(), YesNoEnum.YES.ordinal())) {
            CommonErrors.BAD_REQUEST.check(classResultDTO.getStudentCount().compareTo(existingCount) > 0, "课程人数已满");
        } else {
            CommonErrors.BAD_REQUEST.check(existingCount < CourseConstants.ClassStudentCount.MAX_STUDENT_CONTE, "一个班级下最多只能有300人");
        }

        boolean flag = this.saveRole(dto, ClassRoleEnum.STUDENT, YesNoEnum.NO.ordinal());
        chatRemindSyncService.assistantChangeStudent(dto.getClassId(), dto.getStudentId(), LoginHelper.getXqLoginUser());
        Spring.committed(() -> classMqService.studentIdentitySwitch(dto.getClassId(), dto.getStudentId(), StudentSwitchType.ASSISTANT_TO_STUDENT));

        return flag;
    }

    /**
     * 课代表变助教
     *
     * @param dto 学生实体
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean representativeChangeAssistant(Account user, ClassStudentUpdateDTO dto) {
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(dto.getStudentId()), "学生id不能为空");
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(dto.getClassId()), "班级ID不能为空");
        List<ClassStudentResultDTO> representatives = findByClassIdAndRole(dto.getClassId(), ClassRoleEnum.ASSISTANT);
        CommonErrors.BAD_REQUEST.check(CollectionUtils.isEmpty(representatives), "一个班级只能设置一个助教");
        boolean flag = this.saveRole(dto, ClassRoleEnum.ASSISTANT, YesNoEnum.YES.ordinal());
        //删除原来小组中的学生
        classGroupStudentService.deleteByClassIdAndStudentIdList(user, dto.getClassId(), new ArrayList<>(Collections.singletonList(dto.getStudentId())));
        chatRemindSyncService.representativeChangeAssistant(dto.getClassId(), dto.getStudentId(), LoginHelper.getXqLoginUser());
        Spring.committed(() -> classMqService.studentIdentitySwitch(dto.getClassId(), dto.getStudentId(), StudentSwitchType.STUDENT_TO_ASSISTANT));

        return flag;
    }

    /**
     * 助教变课代表
     *
     * @param dto 学生实体
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean assistantChangeRepresentative(ClassStudentUpdateDTO dto) {
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(dto.getStudentId()), "学生id不能为空");
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(dto.getClassId()), "班级ID不能为空");
        ClassResultDTO classResultDTO = Optional.ofNullable(classService.findById(dto.getClassId())).orElseThrow(() -> CommonErrors.BAD_REQUEST.asException("班级数据不存在"));
        List<ClassStudentResultDTO> representatives = findByClassIdAndRole(dto.getClassId(), ClassRoleEnum.REPRESENTATIVE);
        CommonErrors.BAD_REQUEST.check(CollectionUtils.isEmpty(representatives), "一个班级只能设置一个课代表");

        int addedCount = classService.findAddedClassCountByUserId(dto.getStudentId());
        CommonErrors.BAD_REQUEST.check(addedCount < CourseConstants.ClassCount.STUDENT_ADDED_COUNT, "每个用户最多只能加入五十个班级");
        int existingCount = findAddedCountByClassId(dto.getClassId());
        if (Objects.equals(classResultDTO.getIsStudentCount(), YesNoEnum.YES.ordinal())) {
            CommonErrors.BAD_REQUEST.check(classResultDTO.getStudentCount().compareTo(existingCount) > 0, "课程人数已满");
        } else {
            CommonErrors.BAD_REQUEST.check(existingCount < CourseConstants.ClassStudentCount.MAX_STUDENT_CONTE, "一个班级下最多只能有300人");
        }

        Boolean flag = this.saveRole(dto, ClassRoleEnum.REPRESENTATIVE, YesNoEnum.NO.ordinal());
        chatRemindSyncService.assistantChangeRepresentative(dto.getClassId(), dto.getStudentId(), LoginHelper.getXqLoginUser());
        Spring.committed(() -> classMqService.studentIdentitySwitch(dto.getClassId(), dto.getStudentId(), StudentSwitchType.ASSISTANT_TO_STUDENT));

        return flag;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean searchAndInsertStudent(Long classId, String searchKey, ClassAuditJsonParamDTO auditJson) {
        //班级学生姓名判重
        ClassStudentResultDTO masterExist = this.findByClassIdAndStudentName(classId, auditJson.getStudentName());
        boolean check = Objects.isNull(masterExist) || Objects.equals(auditJson.getStudentName(), masterExist.getStudentName()) && Objects.equals(auditJson.getMobile(), masterExist.getMobile());
        CommonErrors.BAD_REQUEST.check(check, "学生姓名在班级中已存在");

        UserQueryDTO query = new UserQueryDTO();
        query.setSearchKey(searchKey);

        List<UserResultDTO> userList = R.as(userClient.list(query));

        CommonErrors.BAD_REQUEST.check(CollectionUtils.isNotEmpty(userList), "未找到对应的用户");
        CommonErrors.BAD_REQUEST.check(userList.size() == 1, "查询出的用户数据大于一条");

        UserResultDTO user = userList.get(0);

        ClassResultDTO classResult = Optional.ofNullable(classService.findById(classId)).orElseThrow(() -> CommonErrors.BAD_REQUEST.asException(MessageUtils.message("remind.content.class.not.blank")));
        ClassStudentEntity entity = classStudentConvert.create(classId);
        entity.setStudentId(user.getId());
        entity.setClassId(classResult.getId());
        entity.setCourseId(classResult.getCourseId());
        entity.setClassRole(ClassRoleEnum.STUDENT);

        //判断虚拟学生是否有账号
        UserResultDTO userResultDTO = this.checkImitateUserAccount(auditJson.getMobile(), auditJson.getStudentName());

        //判断关系用户是否已加班
        Boolean isInClass = this.checkUserIsInClass(classId, user.getId());

        if (Objects.nonNull(userResultDTO)) {
            if (isInClass) {
                throw CommonErrors.BAD_REQUEST.asException("已加入班级，如需绑定其他学生请更换手机号");
            } else {
                ClassStudentCreateDTO createDTO = new ClassStudentCreateDTO();
                createDTO.setCourseId(classResult.getCourseId());
                createDTO.setClassId(classId);

                Boolean exist = this.checkUserIsInClass(classResult.getId(), userResultDTO.getId());
                if (exist) {
                    this.addRelationStudent(createDTO, auditJson, user.getId(), userResultDTO.getId());
                } else {
                    this.addCoupleStudents(createDTO, auditJson, user.getId(), userResultDTO.getId());
                }
            }
        } else {
            if (isInClass) {
                throw CommonErrors.BAD_REQUEST.asException("已加入班级，如需绑定其他学生请更换手机号");
            } else {
                //创建用户
                userResultDTO = this.imitateUser(auditJson.getMobile(), auditJson.getStudentName());
                ClassStudentCreateDTO createDTO = new ClassStudentCreateDTO();
                createDTO.setCourseId(classResult.getCourseId());
                createDTO.setClassId(classId);
                this.addCoupleStudents(createDTO, auditJson, user.getId(), userResultDTO.getId());
            }
        }

        return true;

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer deleteBatch(List<Long> ids) {
        return baseMapper.deleteBatchIds(ids);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean teacherBatchAddStudent(List<ClassStudentCreateDTO> dto) {
        CommonErrors.BAD_REQUEST.check(CollectionUtils.isNotEmpty(dto), "请选择要添加的学生");
        for (ClassStudentCreateDTO student : dto) {
            student.setClassRole(ClassRoleEnum.STUDENT.getCode());
        }
        saveOrUpdateBatch(dto.stream().map(classStudentConvert::create).collect(Collectors.toList()));
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteByStudentId(Account user, Long studentId) {
        ClassGroupStudentQueryDTO groupStudentQueryDTO = new ClassGroupStudentQueryDTO();
        groupStudentQueryDTO.setStudentId(studentId);
        List<ClassGroupStudentResultDTO> groupStudentResultDTOList = classGroupStudentService.find(groupStudentQueryDTO);
        if (CollectionUtils.isNotEmpty(groupStudentResultDTOList)) {
            classGroupStudentService.batchDelete(user, groupStudentResultDTOList.stream().map(classGroupStudentConvert::convertDel).collect(Collectors.toList()));
        }

        ClassStudentQueryDTO classStudentQueryDTO = new ClassStudentQueryDTO();
        classStudentQueryDTO.setStudentId(studentId);
        List<ClassStudentResultDTO> classStudentResultList = find(classStudentQueryDTO);
        if (CollectionUtils.isNotEmpty(classStudentResultList)) {
            List<Long> idList = classStudentResultList.stream().map(ClassStudentResultDTO::getId).collect(Collectors.toList());
            deleteBatch(idList);
        }

        return true;
    }

    @Override
    public List<ClassStudentEntity> findListContainsTeacherByClassId(Long classId) {
        LambdaQueryWrapper<ClassStudentEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ClassStudentEntity::getClassId, classId);
        return list(wrapper);
    }

    /**
     * 根据班级id列表查询所有学生、包括老师、助教、课代表
     *
     * @param classIdList 班级id列表
     * @return List<ClassStudentEntity>
     */
    @Override
    public List<ClassStudentEntity> findByClassIdList(List<Long> classIdList) {
        LambdaQueryWrapper<ClassStudentEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(ClassStudentEntity::getClassId, classIdList);
        return list(wrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void transferTeacherList(UserResultDTO receiver, List<ClassStudentEntity> teacherList) {

        // 查看转移用户是否是助教 如果是助教 要删除数据
        List<Long> classIds = teacherList.stream().map(ClassStudentEntity::getClassId).collect(Collectors.toList());
        List<ClassStudentEntity> list = findByClassIdListAndStudentId(classIds, receiver.getId());
        this.removeBatchByIds(list);

        for (ClassStudentEntity teacher : teacherList) {
            teacher.setStudentId(receiver.getId());
            teacher.setStudentName(receiver.getNickname());
            teacher.setRelationship(ClassRoleEnum.TEACHER.getDescribe());
        }
        saveOrUpdateBatch(teacherList);
    }

    @Override
    public List<ClassStudentEntity> findByClassIdListAndStudentId(List<Long> classIdList, Long studentId) {
        LambdaQueryWrapper<ClassStudentEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ClassStudentEntity::getStudentId, studentId);
        wrapper.in(ClassStudentEntity::getClassId, classIdList);
        return list(wrapper);
    }

    @Override
    public List<ClassStudentResultDTO> findByClassIdListAndRoleList(List<Long> classIdList, List<ClassRoleEnum> roles) {

        LambdaQueryWrapper<ClassStudentEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(ClassStudentEntity::getClassId, classIdList);
        wrapper.in(ClassStudentEntity::getClassRole, roles);
        return list(wrapper).stream().map(classStudentConvert::convert).collect(Collectors.toList());
    }

    @Override
    public Integer findAddedClassCount() {
        return classService.findAddedClassCountByUserId(LoginHelper.getUserId());
    }

    @Override
    public Long findClassStudentCountByClassId(Long classId) {
        ClassStudentQueryDTO query = new ClassStudentQueryDTO();
        query.setClassId(classId);
        query.setIsTeacher(YesNoEnum.NO.ordinal());
        query.setIsRelationalStudent(YesNoEnum.NO.ordinal());
        return count(wrapper(query));
    }

    @Override
    public ClassStudentResultDTO findByStudentId(Long classId, Long studentId) {
        return this.baseMapper.findByStudentId(classId, studentId);
    }

    @Override
    public List<ClassStudentResultDTO> findByClassRole(Long classId, String classRole) {
        return this.baseMapper.findByClassRole(classId, classRole);
    }

    @Override
    public List<ClassStudentResultDTO> findStudentByStudentIdAndClassId(Long classId, List<Long> studentIds) {
        LambdaQueryWrapper<ClassStudentEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(ClassStudentEntity::getStudentId, studentIds);
        wrapper.eq(ClassStudentEntity::getClassId, classId);
        return classStudentConvert.convertList(list(wrapper));
    }

    @Override
    public ClassStudentEntity findTeacherByClass(Long classId) {
        LambdaQueryWrapper<ClassStudentEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ClassStudentEntity::getClassId, classId);
        wrapper.eq(ClassStudentEntity::getClassRole, ClassRoleEnum.TEACHER.getCode());
        return getOne(wrapper);
    }

    @Override
    public List<ClassStudentEntity> findTeacherListByClassIds(List<Long> classIdList) {
        LambdaQueryWrapper<ClassStudentEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ClassStudentEntity::getClassRole, ClassRoleEnum.TEACHER.getCode());
        wrapper.in(ClassStudentEntity::getClassId, classIdList);
        return list(wrapper);
    }

    @Override
    public ClassStudentEntity getByStudentIdAndClassId(Long studentId, Long classId) {
        LambdaQueryWrapper<ClassStudentEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ClassStudentEntity::getClassId, classId);
        wrapper.eq(ClassStudentEntity::getStudentId, studentId);
        return getOne(wrapper);
    }

    @Override
    public List<ClassStudentEntity> findAllByClassId(Long classId) {
        LambdaQueryWrapper<ClassStudentEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ClassStudentEntity::getClassId, classId);
        return list(wrapper);
    }

    @Override
    public List<ClassStudentEntity> findTeacherAssistantByClass(Long classId) {
        LambdaQueryWrapper<ClassStudentEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ClassStudentEntity::getClassId, classId);
        wrapper.in(ClassStudentEntity::getClassRole, ClassRoleEnum.TEACHER.getCode(), ClassRoleEnum.ASSISTANT.getCode());
        return list(wrapper);
    }

    private Boolean saveRole(ClassStudentUpdateDTO dto, ClassRoleEnum classRole, Integer isTeacher) {
        dto.setClassRole(classRole.getCode());
        dto.setIsTeacher(isTeacher);
        ClassStudentEntity entity = classStudentConvert.update(dto);
        return updateById(entity);
    }

    /**
     * 判断学生是否在班级
     */
    @Override
    public void checkStudentInClass(Long classId, Long studentId) {
        ClassStudentEntity studentEntity = this.selectByClassIdAndStudentId(classId, studentId);
        if (Objects.isNull(studentEntity) || Objects.equals(ClassRoleEnum.TEACHER, studentEntity.getClassRole()) || Objects.equals(ClassRoleEnum.ASSISTANT, studentEntity.getClassRole())) {
            CommonErrors.BAD_REQUEST.check(false, MessageUtils.message("assistant.data.not.valid"));
        }
    }

    /**
     * 判断老师是否在班级
     */
    @Override
    public void checkTeacherInClass(Long classId, Long studentId) {
        ClassStudentEntity studentEntity = this.selectByClassIdAndStudentId(classId, studentId);
        if (Objects.isNull(studentEntity) || Objects.equals(ClassRoleEnum.STUDENT, studentEntity.getClassRole()) || Objects.equals(ClassRoleEnum.ASSISTANT, studentEntity.getClassRole())) {
            CommonErrors.BAD_REQUEST.check(false, MessageUtils.message("assistant.data.not.valid"));
        }
    }

    /**
     * 获取班级学生列表不包括注销学生
     */
    @Override
    public List<ClassStudentResultDTO> studentListByClassId(Long classId) {
        return this.baseMapper.selectClassStudents(classId).stream().map(classStudentConvert::convert).collect(Collectors.toList());
    }

    /**
     * 获取班级所有成员列表不包括注销用户
     */
    @Override
    public List<ClassStudentResultDTO> allUserListByClassId(Long classId) {
        return this.baseMapper.selectClassAllUser(classId).stream().map(classStudentConvert::convert).collect(Collectors.toList());
    }

    /**
     * 获取班级学生老师列表不包括注销用户
     */
    @Override
    public List<ClassStudentResultDTO> findContainsTeacherListByClassId(Long classId) {
        return this.baseMapper.findContainsTeacherListByClassId(classId).stream().map(classStudentConvert::convert).collect(Collectors.toList());
    }

    @Override
    public void saveAllStudent(List<ClassStudentEntity> list) {
        this.saveOrUpdateBatch(list);
    }

    @Override
    public ClassStudentResultDTO findByClassIdAndMobile(Long classId, String mobile) {
        UserResultDTO user = R.as(userClient.findByMobile(mobile));
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(user), "未找到对应的用户");

        ClassStudentResultDTO resultStudent = classStudentConvert.convert(user);
        resultStudent.setNickName(user.getNickname());

        ClassStudentResultDTO classStudent = this.baseMapper.findByStudentId(classId, user.getId());
        if (Objects.nonNull(classStudent)) {
            resultStudent.setIsTeacher(classStudent.getIsTeacher());
            resultStudent.setClassRole(classStudent.getClassRole());
            resultStudent.setClassId(classStudent.getClassId());
            resultStudent.setCourseId(classStudent.getCourseId());
            resultStudent.setStudentId(classStudent.getStudentId());
            resultStudent.setStudentName(classStudent.getStudentName());
            resultStudent.setRelationship(classStudent.getRelationship());
            resultStudent.setIsRelationalStudent(classStudent.getIsRelationalStudent());
            resultStudent.setPatStuRefId(classStudent.getPatStuRefId());
        }

        return resultStudent;
    }

    @Override
    public Boolean addAssistant(Long classId, Long userId) {
        UserResultDTO user = R.as(userClient.findById(userId));
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(user), "要添加的助教不存在");

        ClassResultDTO classResultDTO = Optional.ofNullable(classService.findById(classId)).orElseThrow(() -> CommonErrors.BAD_REQUEST.asException("班级数据不存在"));

        CommonErrors.BAD_REQUEST.check(CollectionUtils.isEmpty(this.findByClassIdAndRole(classId, ClassRoleEnum.ASSISTANT)), "每个班级只能有一个助教");
        CommonErrors.BAD_REQUEST.check(Objects.isNull(this.findByClassIdAndStudentId(classId, userId, YesNoEnum.YES.ordinal())), "已是该班级成员");

        ClassStudentEntity entity = classStudentConvert.convert(classResultDTO.getCourseId(), classId, userId);
        entity.setIsTeacher(YesNoEnum.YES.ordinal());
        entity.setIsTop(YesNoEnum.NO.ordinal());
        entity.setClassRole(ClassRoleEnum.ASSISTANT);
        entity.setCreateBy(LoginHelper.getUserId());

        entity.setStudentName(user.getNickname());
        entity.setRelationship(ClassRoleEnum.ASSISTANT.getDescribe());
        save(entity);
        classMqService.addAssistant(classId, userId, LoginHelper.getXqLoginUser());
        return true;
    }

    /**
     * 这个接口查出来的都是主学生（兼容历史数据）
     *
     * @param classId 班级id
     * @param userId  用户id
     * @return ClassStudentResultDTO
     */
    @Override
    public ClassStudentResultDTO findVirtualClassStudentByClassIdAndUserId(Long classId, Long userId) {
        return this.baseMapper.findVirtualClassStudentByClassIdAndUserId(classId, userId);
    }

    /**
     * 根据主用户id 查询关系用户集合
     *
     * @param classId 班级id
     * @param userIds 用户id集合
     * @return ClassStudentResultDTO
     */
    @Override
    public List<ClassStudentResultDTO> findRelationshipStudentByClassIdAndUserIds(Long classId, List<Long> userIds) {
        return this.baseMapper.findClassIdAndByMasterIdList(classId, userIds);
    }

    @Override
    public List<ClassStudentResultDTO> findRelationStudentByClassIdAndImitateStudentId(Long classId, Long studentId) {

        List<ClassStudentResultDTO> list = this.baseMapper.findRelationStudentByClassIdAndImitateStudentId(classId, studentId);

        // 获取主学生信息
        ClassStudentResultDTO mainStudent = this.findVirtualClassStudentByClassIdAndUserId(classId, LoginHelper.getUserId());
        // 校验查询主用户信息是否等于 查看用户主信息 不等于 手机号隐藏
        if (Objects.nonNull(mainStudent) && !Objects.equals(studentId, mainStudent.getStudentId())) {
            list.forEach(item -> {
                item.setMobile(DesensitizedUtil.mobilePhone(item.getMobile()));
            });
        }

        return list;
    }

    /**
     * 批量移除关系学生，实际上多个关系用户有可能对应一个主学生
     *
     * @param classId 班级id
     * @param dtoList 关系用户列表
     * @return Boolean
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean teacherRemoveRelationalStudentBatch(Long classId, List<ClassStudentDeleteDTO> dtoList) {
        CommonErrors.BAD_REQUEST.check(CollectionUtils.isNotEmpty(dtoList), "请选择要移除的学生");
        ClassResultDTO classResult = Optional.ofNullable(classService.findById(classId)).orElseThrow(() -> CommonErrors.BAD_REQUEST.asException(MessageUtils.message("remind.content.class.not.blank")));

        //注意：删除关系学生时要注意过滤掉主学生，防止前端调错接口破坏数据完整性
        List<ClassStudentEntity> relationStudentList = this.findStudentByClassIdAndIsRelationshipAndIds(classId, YesNoEnum.YES.ordinal(), dtoList.stream().map(ClassStudentDeleteDTO::getId).collect(Collectors.toList()));

        //如果列表为空，说明参数传错了
        if (CollectionUtils.isNotEmpty(relationStudentList)) {
            Set<Long> relationStudentIdSet = dtoList.stream().map(ClassStudentDeleteDTO::getId).collect(Collectors.toSet());
            this.baseMapper.deleteBatchIds(relationStudentIdSet);

            //退课记录
            Set<Long> operaStudentIdSet = relationStudentList.stream().map(ClassStudentEntity::getStudentId).collect(Collectors.toSet());
            classOperationLogService.batchInsertStudentOperateLog(classResult.getCourseId(), classId, new ArrayList<>(operaStudentIdSet), null, ClassOperationLogTypeEnum.MOVE_OUT);

            //删除审核记录
            classJoinAuditService.deleteByClassIdAndStudentIdList(classId, new ArrayList<>(operaStudentIdSet));

            //发消息
            Spring.committed(() -> relationStudentList.forEach(relation -> classMqService.studentQuitClass(classId, relation.getStudentId(), relation.getStudentName() + relation.getRelationship(), LoginHelper.getXqLoginUser())));
        }
        return true;
    }

    @Override
    public List<ClassStudentEntity> findStudentByClassIdAndIsRelationshipAndIds(Long classId, Integer isRelationStudent, List<Long> ids) {
        LambdaQueryWrapper<ClassStudentEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ClassStudentEntity::getClassId, classId);
        wrapper.eq(ClassStudentEntity::getIsRelationalStudent, isRelationStudent);
        wrapper.eq(ClassStudentEntity::getIsTeacher, YesNoEnum.NO.ordinal());
        wrapper.in(ClassStudentEntity::getId, ids);
        return list(wrapper);
    }

    @Override
    public List<ClassStudentResultDTO> findClassMasterStudentByClassId(Long classId) {
        ClassStudentQueryDTO query = new ClassStudentQueryDTO();
        query.setClassId(classId);
        query.setIsTeacher(YesNoEnum.NO.ordinal());
        query.setIsRelationalStudent(YesNoEnum.NO.ordinal());
        return list(wrapper(query)).stream().map(classStudentConvert::convert).collect(Collectors.toList());
    }

    @Override
    public List<ClassStudentResultDTO> findClassRelationStudentByClassId(Long classId) {
        ClassStudentQueryDTO query = new ClassStudentQueryDTO();
        query.setClassId(classId);
        query.setIsTeacher(YesNoEnum.NO.ordinal());
        query.setIsRelationalStudent(YesNoEnum.YES.ordinal());
        return list(wrapper(query)).stream().map(classStudentConvert::convert).collect(Collectors.toList());
    }

    @Override
    public List<ClassStudentResultDTO> findClassMasterStudentByClassIdList(List<Long> classIdList) {
        return classStudentConvert.convertList(this.baseMapper.findClassMasterStudentByClassIdList(classIdList));
    }

    @Transactional(rollbackFor = Exception.class)
    public void removeRelationalStudentBatch(Long classId, List<Long> masterIdList) {
        CommonErrors.BAD_REQUEST.check(CollectionUtils.isNotEmpty(masterIdList), "学生ID不能全为空");
        List<ClassStudentEntity> relationStudentEntityList = this.findRelationStudentListByClassIdAndMasterIdList(classId, masterIdList);
        if (CollectionUtils.isNotEmpty(relationStudentEntityList)) {
            List<Long> relationIdList = relationStudentEntityList.stream().map(ClassStudentEntity::getId).collect(Collectors.toList());
            //删除学生列表
            this.deleteBatch(relationIdList);

            List<Long> relationStudentIdList = relationStudentEntityList.stream().map(ClassStudentEntity::getStudentId).collect(Collectors.toList());
            //删除审核记录
            classJoinAuditService.deleteByClassIdAndStudentIdList(classId, relationStudentIdList);
            //退课记录
            classOperationLogService.batchInsertStudentOperateLog(relationStudentEntityList.get(0).getCourseId(), classId, relationStudentIdList, null, ClassOperationLogTypeEnum.MOVE_OUT);
            //发消息
            relationStudentEntityList.forEach(relation -> classMqService.studentQuitClass(classId, relation.getStudentId(), relation.getStudentName() + relation.getRelationship(), LoginHelper.getXqLoginUser()));
        }

    }

    public List<ClassStudentEntity> findRelationStudentListByClassIdAndMasterIdList(Long classId, List<Long> masterIdList) {
        return this.baseMapper.findRelationStudentListByClassIdAndMasterIdList(classId, masterIdList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateMasterStudent(MasterClassStudentUpdateDTO dto) {

        ClassStudentResultDTO classStudentResultDTO = this.baseMapper.findDetailById(dto.getClassStudentId());
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(classStudentResultDTO), "班级学生不存在");

        if (Objects.nonNull(dto.getNickName())) {
            ClassStudentResultDTO existName = this.findByClassIdAndStudentName(classStudentResultDTO.getClassId(), dto.getNickName());
            CommonErrors.BAD_REQUEST.check(Objects.isNull(existName) || Objects.equals(dto.getClassStudentId(), existName.getId()), "班级学生姓名已存在");
        }

        // 判重
        // UserResultDTO existUser = R.as(userClient.findImitateByMobileAndNickname(classStudentResultDTO.getMobile(), classStudentResultDTO.getNickName()));
        // CommonErrors.BAD_REQUEST.check(Objects.isNull(existUser) || Objects.equals(existUser.getId(), classStudentResultDTO.getStudentId()), "手机号+学生姓名已存在，请确认手机号或更换学生姓名");

        //修改虚拟主学生和关系用户数据
        List<ClassStudentEntity> classStudentList = this.findMasterAndRelationStudentByClassIdAndImitateStudentId(classStudentResultDTO.getClassId(), classStudentResultDTO.getStudentId());
        this.setClassStudentAttributes(classStudentList, dto);
        this.updateBatchById(classStudentList);

        // 更新加班审核信息
        List<Long> studentIds = classStudentList.stream().map(ClassStudentEntity::getStudentId).collect(Collectors.toList());
        List<ClassJoinAuditResultDTO> auditList = classJoinAuditService.findByClassIdAndStudentIdList(classStudentResultDTO.getClassId(), studentIds);
        if (CollectionUtils.isNotEmpty(auditList)) {
            //增量更新学生加班审核信息
            List<ClassJoinAuditEntity> list = this.setClassJoinAttributes(auditList, dto);
            if (CollectionUtils.isNotEmpty(list)) {
                classJoinAuditManager.updateBatchById(list);
            }
        }

        //修改主用户数据
        UserImitateUpdateDTO updateDTO = classStudentConvert.convert(dto);
        updateDTO.setUserId(classStudentResultDTO.getStudentId());
        if (Objects.nonNull(dto.getNickName())) {
            updateDTO.setOldNickName(dto.getNickName());
        }
        if (Objects.nonNull(dto.getMobile())) {
            updateDTO.setOldMobile(dto.getMobile());
        }
        // 学号必传字段
        updateDTO.setStudentNumber(dto.getStudentNumber());

        userClient.imitateUserUpdate(updateDTO);

        return true;
    }

    @Override
    public List<ClassStudentEntity> findMasterAndRelationStudentByClassIdAndImitateStudentId(Long classId, Long studentId) {
        LambdaQueryWrapper<ClassStudentEntity> wrapper = Queries.lambda();

        wrapper.eq(ClassStudentEntity::getClassId, classId)
            .eq(ClassStudentEntity::getStudentId, studentId)
            .eq(ClassStudentEntity::getIsRelationalStudent, YesNoEnum.NO.ordinal())
            .or()
            .eq(ClassStudentEntity::getClassId, classId)
            .eq(ClassStudentEntity::getPatStuRefId, studentId)
            .eq(ClassStudentEntity::getIsRelationalStudent, YesNoEnum.YES.ordinal());
        return list(wrapper);
    }

    @Override
    public List<ClassStudentEntity> findMasterAndRelationStudentByClassIdAndRelationStudentId(Long classId, Long relationId) {
        return this.baseMapper.findMasterAndRelationStudentByClassIdAndRelationStudentId(classId, relationId);
    }

    @Override
    public List<ClassStudentMobileResultDTO> findImitateStudentMobileList(ClassImitateStudentQueryDTO dto) {
        // 获取班级 学生信息
        LambdaQueryWrapper<ClassStudentEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ClassStudentEntity::getClassId, dto.getClassId());
        wrapper.eq(ClassStudentEntity::getStudentName, dto.getStudentName().trim());
        wrapper.eq(ClassStudentEntity::getIsTeacher, YesNoNumberEnum.NO.getCode());
        wrapper.eq(ClassStudentEntity::getIsRelationalStudent, YesNoEnum.NO.ordinal());
        List<ClassStudentEntity> studentEntityList = list(wrapper);

        List<ClassStudentMobileResultDTO> mobileList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(studentEntityList)) {
            studentEntityList.forEach(student -> {
                UserResultDTO user = R.as(userClient.findById(student.getStudentId()));
                if (Objects.nonNull(user)) {
                    ClassStudentMobileResultDTO mobileResult = new ClassStudentMobileResultDTO();
                    mobileResult.setLabel(DesensitizedUtil.mobilePhone(String.valueOf(user.getMobile())));
                    mobileResult.setValue(String.valueOf(user.getMobile()));
                    mobileList.add(mobileResult);
                }
            });
        } else {
            // 班级信息中没有此学生 校验审核列表中是否存在此姓名信息
            LambdaQueryWrapper<ClassJoinAuditEntity> joinWrapper = new LambdaQueryWrapper<>();
            joinWrapper.eq(ClassJoinAuditEntity::getClassId, dto.getClassId());
            joinWrapper.eq(ClassJoinAuditEntity::getStatus, YesNoNumberEnum.NO.getCode());
            joinWrapper.apply("json_contains(audit_content, '{\"学生真实姓名\":\"" + dto.getStudentName().trim() + "\"}')");
            List<ClassJoinAuditEntity> joinList = classJoinAuditManager.list(joinWrapper);
            if (CollectionUtils.isNotEmpty(joinList)) {
                studentEntityList.forEach(item -> {
                    JSONObject jsonObject = JSONObject.parseObject(item.getAuditContent());
                    Object mobileObj = jsonObject.get(ClassAuditJsonParamEnum.学生绑定手机号.getCode());
                    ClassStudentMobileResultDTO mobileResult = new ClassStudentMobileResultDTO();
                    mobileResult.setLabel(DesensitizedUtil.mobilePhone(String.valueOf(mobileObj)));
                    mobileResult.setValue(String.valueOf(mobileObj));
                    mobileList.add(mobileResult);
                });
            }
        }

        return mobileList;
    }

    /**
     * 先更新学生表中的审核信息
     *
     * @param classId
     * @param dto
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void repairAuditContent(Long classId, ClassStudentAuditData dto) {
        CommonErrors.BAD_REQUEST.check(CollectionUtils.isNotEmpty(dto.getDataList()), "报名信息不能为空");

        // 获取主班级信息
        ClassStudentResultDTO mainStudent = classStudentService.findVirtualClassStudentByClassIdAndUserId(classId, LoginHelper.getUserId());
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(mainStudent), "班级学生信息不存在");

        List<ClassStudentEntity> classStudentList = this.findMasterAndRelationStudentByClassIdAndRelationStudentId(classId, mainStudent.getStudentId());
        CommonErrors.BAD_REQUEST.check(CollectionUtils.isNotEmpty(classStudentList), "班级学生信息不存在");

        //增量更新学生表信息
        this.setRestAuditAttributes(classStudentList, dto);
        this.updateBatchById(classStudentList);

        // 更新审核信息
        List<Long> studentIds = classStudentList.stream().map(ClassStudentEntity::getStudentId).collect(Collectors.toList());
        List<ClassJoinAuditResultDTO> auditList = classJoinAuditService.findByClassIdAndStudentIdList(classId, studentIds);
        if (CollectionUtils.isNotEmpty(auditList)) {
            //增量更新学生加班审核信息
            List<ClassJoinAuditEntity> list = this.setRestJoinAuditAttributes(auditList, dto);
            if (CollectionUtils.isNotEmpty(list)) {
                classJoinAuditManager.updateBatchById(list);
            }
        }


    }

    @Override
    public ClassStudentResultDTO findClassStudentContainTeacherByClassIdAndUserId(Long classId, Long userId) {

        // 获取主学生信息
        ClassStudentResultDTO classMasterStudent = this.baseMapper.findClassStudentContainTeacherByClassIdAndUserId(classId, userId);

        // 获取登录用户信息
        ClassStudentResultDTO loginStudent = this.findByClassIdAndStudentId(classId, LoginHelper.getUserId());
        if (Objects.nonNull(loginStudent) && Objects.nonNull(classMasterStudent)
            && Objects.equals(YesNoNumberEnum.NO.getCode(), loginStudent.getIsTeacher())) {
            //当前登录人与模拟学生之间的亲属关系
            if (Objects.equals(classMasterStudent.getStudentId(), loginStudent.getPatStuRefId())) {
                classMasterStudent.setKinship(loginStudent.getRelationship());
            } else {
                // 学生ID 不等于 关系用户绑定学生ID 隐藏手机号
                if (Objects.equals(YesNoNumberEnum.NO.getCode(), classMasterStudent.getIsTeacher())) {
                    classMasterStudent.setMobile(DesensitizedUtil.mobilePhone(classMasterStudent.getMobile()));
                }
            }

        }

        return classMasterStudent;
    }

    @Override
    public Boolean teacherRemoveAssistant(Account xqLoginUser, Long classId, Long assistantId) {
        ClassStudentResultDTO assistant = findByClassAndClassStudentIdAndClasRole(classId, assistantId, ClassRoleEnum.ASSISTANT);
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(assistant), "要删除的助教信息不存在");
        return removeById(assistant.getId());
    }

    @Override
    public ClassStudentResultDTO findByClassAndClassStudentIdAndClasRole(Long classId, Long id, ClassRoleEnum classRole) {
        LambdaQueryWrapper<ClassStudentEntity> wrapper = Queries.lambda();
        wrapper.eq(ClassStudentEntity::getClassId, classId);
        wrapper.eq(ClassStudentEntity::getId, id);
        wrapper.eq(ClassStudentEntity::getClassRole, classRole);
        return classStudentConvert.convert(getOne(wrapper));
    }

    @Override
    public ClassStudentResultDTO findByClassIdAndStudentName(Long classId, String studentName) {
        LambdaQueryWrapper<ClassStudentEntity> wrapper = Queries.lambda();
        wrapper.eq(ClassStudentEntity::getClassId, classId);
        wrapper.eq(ClassStudentEntity::getStudentName, studentName);
        wrapper.eq(ClassStudentEntity::getIsTeacher, YesNoEnum.NO.ordinal());
        wrapper.eq(ClassStudentEntity::getIsRelationalStudent, YesNoEnum.NO.ordinal());
        wrapper.last("LIMIT 1");
        ClassStudentResultDTO studentResultDTO = classStudentConvert.convert(getOne(wrapper));
        if (Objects.isNull(studentResultDTO)) {
            return null;
        }

        JSONObject auditContent = JSON.parseObject(studentResultDTO.getAuditContent(), JSONObject.class);
        if (Objects.nonNull(auditContent)) {
            studentResultDTO.setMobile((String) auditContent.get(ClassAuditJsonParamEnum.学生绑定手机号.getCode()));
        }

        return studentResultDTO;
    }

    /**
     * 增量添加
     */
    private void setRestAuditAttributes(List<ClassStudentEntity> classStudentList, ClassStudentAuditData dto) {
        if (CollectionUtils.isEmpty(classStudentList)) {
            return;
        }

        for (ClassStudentEntity entity : classStudentList) {

            Map<String, String> auditMap = new HashMap<>();
            if (Objects.nonNull(entity.getAuditContent())) {
                auditMap = JSON.parseObject(entity.getAuditContent(), new TypeReference<Map<String, String>>() {});
            }

            for (ClassStudentAuditData.DataItem data : dto.getDataList()) {
                if (!auditMap.containsKey(data.getKey())) {
                    auditMap.put(data.getKey(), String.valueOf(data.getValue()));
                }
            }

            entity.setAuditContent(JSON.toJSONString(auditMap));
        }

    }

    /**
     * 审核信息增量添加
     */
    private List<ClassJoinAuditEntity> setRestJoinAuditAttributes(List<ClassJoinAuditResultDTO> auditList, ClassStudentAuditData dto) {

        List<ClassJoinAuditEntity> updateList = new ArrayList<>();

        for (ClassJoinAuditResultDTO item : auditList) {

            // 遍历加入班级审核信息内容
            List<Map<String, String>> mapList = (List<Map<String, String>>) JSONArray.parse(item.getAuditContent());

            // 补充审核信息
            dto.getDataList().forEach(data -> {
                // 校验加入班级审核信息是否包含额外审核内容
                boolean flag = true;
                for (Map<String, String> map : mapList) {
                    if (map.containsKey(data.getKey())) {
                        flag = false;
                    }
                }
                if (flag) {
                    Map<String, String> map = new HashMap<>();
                    map.put(data.getKey(), data.getValue().toString());
                    mapList.add(map);

                    ClassJoinAuditEntity entity = new ClassJoinAuditEntity();
                    entity.setId(item.getId());
                    // 赋值加班审核信息
                    entity.setAuditContent(JSON.toJSONString(mapList));
                    updateList.add(entity);
                }
            });
        }

        return updateList;

    }

    /**
     * 设置学生的学生姓名、审核数据
     *
     * @param classStudentEntityList
     * @param dto
     */
    private void setClassStudentAttributes(List<ClassStudentEntity> classStudentEntityList, MasterClassStudentUpdateDTO dto) {
        if (CollectionUtils.isNotEmpty(classStudentEntityList)) {
            for (ClassStudentEntity classStudentEntity : classStudentEntityList) {

                JSONObject jsonObject = new JSONObject();
                if (StringUtils.isNotEmpty(classStudentEntity.getAuditContent())) {
                    jsonObject = JSONObject.parseObject(classStudentEntity.getAuditContent());
                }
                if (StringUtils.isNotEmpty(dto.getNickName())) {
                    classStudentEntity.setStudentName(dto.getNickName());
                    jsonObject.put(ClassAuditJsonParamEnum.学生真实姓名.getCode(), dto.getNickName());
                }
                if (StringUtils.isNotEmpty(dto.getMobile())) {
                    jsonObject.put(ClassAuditJsonParamEnum.学生绑定手机号.getCode(), dto.getMobile());
                }
                classStudentEntity.setAuditContent(jsonObject.toJSONString());
            }
        }
    }

    /**
     * 设置加入班级的学生姓名、审核数据
     * @param auditList
     * @param dto
     */
    private List<ClassJoinAuditEntity> setClassJoinAttributes(List<ClassJoinAuditResultDTO> auditList, MasterClassStudentUpdateDTO dto) {
        List<ClassJoinAuditEntity> list = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(auditList)) {
            for (ClassJoinAuditResultDTO item : auditList) {
                if (StringUtils.isNotEmpty(item.getAuditContent())) {
                    // 遍历加入班级审核信息内容
                    List<Map<String, String>> mapList = (List<Map<String, String>>) JSONArray.parse(item.getAuditContent());
                    for (Map<String, String> map : mapList) {
                        if (map.containsKey(ClassAuditJsonParamEnum.学生真实姓名.getCode())) {
                            map.put(ClassAuditJsonParamEnum.学生真实姓名.getCode(), dto.getNickName());
                        } else if(map.containsKey(ClassAuditJsonParamEnum.学生绑定手机号.getCode())) {
                            map.put(ClassAuditJsonParamEnum.学生绑定手机号.getCode(), dto.getMobile());
                        }
                    }
                    ClassJoinAuditEntity entity = new ClassJoinAuditEntity();
                    entity.setId(item.getId());
                    entity.setAuditContent(JSON.toJSONString(mapList));
                    list.add(entity);
                }
            }
        }
        return list;
    }

    @Override
    public Long findAllCountByClassId(Long classId) {
        ClassStudentQueryDTO query = new ClassStudentQueryDTO();
        query.setClassId(classId);
        return count(wrapper(query));
    }

    @Transactional(rollbackFor = Exception.class)
    public void removeMasterBatch(Account user, Long classId, List<Long> idList) {
        CommonErrors.BAD_REQUEST.check(CollectionUtils.isNotEmpty(idList), "学生ID不能全为空");
        List<ClassStudentEntity> studentEntityList = findListByIds(idList);
        CommonErrors.BAD_REQUEST.check(CollectionUtils.isNotEmpty(studentEntityList), "学生数据不存在");
        //注意：删除主学生时要注意过滤掉老师和关系学生，防止前端调错接口破坏数据完整性
        List<Long> studentIdList = studentEntityList.stream()
            .filter(st -> Objects.equals(YesNoEnum.NO.ordinal(), st.getIsTeacher()))
            .filter(st -> Objects.equals(YesNoEnum.NO.ordinal(), st.getIsRelationalStudent()))
            .map(ClassStudentEntity::getStudentId).collect(Collectors.toList());

        if (CollectionUtils.isNotEmpty(studentIdList)) {
            //删除学生列表
            deleteBatch(idList);

            //删除小组成员列表
            classGroupStudentService.deleteByClassIdAndStudentIdList(user, classId, studentIdList);
        }
    }
}
